#pragma once

#include <string>

#include "./Noncopyable.h"

// 宏定义放在前面便于用户查看定义并使用
// 在前面可以使用后面定义的LogLevel::INFO

// 课程觉得库日志代码不好：c++很多都是流式输出，建议用格式化输出（因为拼接信息直观）
// ##__VA_ARGS__。## 是 GNU 扩展语法，用于在可变参数为空时移除多余的逗号
// 宏有多行，使用do while包裹为一个作用域，避免外部在if{}else{}等使用宏展开后作用域意外错误

// LOG_INFO("%s %d", arg1, arg2)
#define LOG_INFO(logMsgFormat, ...)                       \
    do                                                    \
    {                                                     \
        Logger &logger = Logger::getInstance();           \
                                                          \
        logger.setLogLevel(LogLevel::INFO);               \
        char buf[1024]{0};                                \
        snprintf(buf, 1024, logMsgFormat, ##__VA_ARGS__); \
                                                          \
        logger.log(buf);                                  \
    } while (0)

#define LOG_ERROR(logMsgFormat, ...)                      \
    do                                                    \
    {                                                     \
        Logger &logger = Logger::getInstance();           \
                                                          \
        logger.setLogLevel(LogLevel::ERROR);              \
        char buf[1024]{0};                                \
        snprintf(buf, 1024, logMsgFormat, ##__VA_ARGS__); \
                                                          \
        logger.log(buf);                                  \
    } while (0)

#define LOG_FATAL(logMsgFormat, ...)                      \
    do                                                    \
    {                                                     \
        Logger &logger = Logger::getInstance();           \
                                                          \
        logger.setLogLevel(LogLevel::FATAL);              \
        char buf[1024]{0};                                \
        snprintf(buf, 1024, logMsgFormat, ##__VA_ARGS__); \
                                                          \
        logger.log(buf);                                  \
                                                          \
        exit(-1);                                         \
    } while (0)

// 一般debug信息多，可以定义一个宏进行关闭
#ifdef LOGGER_DEBUG
#define LOG_DEBUG(logMsgFormat, ...)                      \
    do                                                    \
    {                                                     \
        Logger &logger = Logger::getInstance();           \
                                                          \
        logger.setLogLevel(LogLevel::DEBUG);              \
        char buf[1024]{0};                                \
        snprintf(buf, 1024, logMsgFormat, ##__VA_ARGS__); \
                                                          \
        logger.log(buf);                                  \
    } while (0)
#else
#define LOG_DEBUG(logMsgFormat, ...)
#endif

// OPTIMIZE: enum -> enum class
enum class LogLevel
{
    INFO,  // 普通信息
    ERROR, // 错误信息，不影响继续执行
    FATAL, // core dump信息，影响继续执行
    DEBUG  // 调试信息
};

class Logger : Noncopyable
{
public:
    static Logger &getInstance();

    void setLogLevel(const LogLevel logLevel);
    void log(const std::string msg);

private:
    LogLevel logLevel_ = LogLevel::INFO; // 默认普通信息
};